package scalab.filters.misc

import scalab.core.component.{Component, Filter}

/**
* Allows to make a byte-wise comparison of dependencies received on each separated input.
*	If the equality is respected, the dependencies are yield. Otherwise an error is generated.
*/

trait SameContent extends Filter{
	import scalab.core.dependencies.Dependency
	import scalab.utils.MD5
	def execute: Boolean = {
		
		
		if(!inputs.isEmpty){

			var res: Pair[Boolean, List[List[Dependency]]] = (true, inputs map {i => i.orderedSources.toList})

			do{
				res = same(res._2)
			}while(res._1 == true && !(res._2 exists {l => l.isEmpty}))
			
			if(res._1)
				forward(inputs.head.component)
			res._1
		}
		else
			true
	}
	override def instanceId: String = ""

	def same(lsts: List[List[Dependency]]): Pair[Boolean, List[List[Dependency]]] = {
		if(lsts exists {l => l.isEmpty})
			(lsts forall {t => t.isEmpty}, lsts)
		else{
			val firstDep = lsts.head.head
			val first = MD5.digestContent(firstDep)
			val tails = lsts map {l => l.tail}
			(lsts.tail forall {l: List[Dependency] => 
					val res = first == MD5.digestContent(l.head)
					if(!res)
						error("The contents of the following files do not match:\n\t" + firstDep.getPath + "\n\t" + l.head.getPath)
					res
				} ,tails)
		}
	}
	
	/*def stream(streams: List[Stream[Dependency]]): Stream[List[Dependency]] = 
		Stream.cons((streams map {s => if(s.isEmpty)null else s.head}), stream(streams map {s => if(s.isEmpty)Stream.empty else s.tail}))

	def stream2(str: Stream[List[Dependency]]): Stream[List[Dependency]] = {
		val head = str.head
		Stream.cons(head, if(head exists {d => d != null})str.tail else Stream.empty)
	}*/
}

object SameContent{
	def apply(componentName: String, nbInputs: Int): SameContent = {
		val sc = new SameContent{
			override val name: String = componentName
		}
		List.range(0, nbInputs) foreach {i => sc.mandatoryIn}
		sc
	}

	def apply(nbInputs: Int): SameContent = apply("SameContent", nbInputs)

	def apply(componentName: String, components: Iterable[Component]): SameContent = {
		val sc = new SameContent{
			override val name: String = componentName
			components foreach {c => c -> mandatoryIn}
		}
		sc
	}

	def apply(componentName: String, components: Component*): SameContent = 
		apply(componentName, components)

	def apply(components: Iterable[Component]): SameContent = 
		apply("SameContent", components)

	def apply(components: Component*): SameContent = 
		apply(components)
}
